﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using Windows.Devices.Geolocation;


namespace SNSComponent.SNSProvider
{
    public class SinaProvider : BaseOAuth2Provider
    {
        protected string AccessToken { get; private set; }

        public DateTime ExpressDate { get; private set; }

        public string UserID { get; private set; }

        public DateTime AuthDate { get; private set; }


        public SinaProvider(string appKey, string appSecret, Uri redirectUri, string providerName)
            : base(appKey, appSecret, redirectUri, providerName)
        {

        }

        protected override Uri GetAuthUri()
        {
            return new Uri(string.Format("https://api.weibo.com/oauth2/authorize?client_id={0}&response_type=code&redirect_uri={1}&display=mobile",
                System.Net.HttpUtility.UrlEncode(AppKey),
                System.Net.HttpUtility.UrlEncode(RedirectUri.ToString())));
        }

        string _veriferCode;
        protected override void OnUserAuthing(object sender, UserAuthEventArgs e)
        {
            if (e.VerifierUri.Query.ToLower().Contains("code="))
            {
                string[] tmp = e.VerifierUri.Query.Split('=');
                if (tmp.Length >= 2)
                {
                    _veriferCode = tmp[1];
                    e.IsAuth = true;
                }

            }
        }

        protected override async Task<ResultData> GetAccessToken(Uri verifyUri)
        {
            Uri postUri = new Uri(string.Format("https://api.weibo.com/oauth2/access_token?client_id={0}&client_secret={1}&grant_type=authorization_code&redirect_uri={2}&code={3}",
                System.Net.HttpUtility.UrlEncode(AppKey),
                System.Net.HttpUtility.UrlEncode(AppSecret),
                RedirectUri.ToString(),
                System.Net.HttpUtility.UrlEncode(_veriferCode)));

           
            Dictionary<string, string> header = new Dictionary<string, string>();
            header.Add("Content-Type", "application/x-www-form-urlencoded");
            try
            {
                return await Utiltiy.HttpUtility.Post(postUri,null, header, (webResponse) =>
                {
                    using (System.IO.Stream stream = webResponse.GetResponseStream())
                    {
                        System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SinaWeiboAuthInfor));

                        SinaWeiboAuthInfor authInfor = serializer.ReadObject(stream) as SinaWeiboAuthInfor;
                        if (authInfor != null)
                        {

                            this.AccessToken = authInfor.AccessToken;
                            this.AuthDate = DateTime.Now;
                            this.ExpressDate = DateTime.Now.AddSeconds(authInfor.ExpressionIn);
                            this.UserID = authInfor.UserID;

                            IsAuthed = true;
                        }
                        ResultData result = new ResultData(this, ResultState.Success);

                        return result;
                    }

                });
            }
            catch (WebException webEx)
            {
                return WebExcptionHandler(webEx);
            }
            catch (Exception ex)
            {
                return new ResultData(this, ResultState.UnknowError, ex);
            }
        }

        #region Share Status

        public override async Task<ResultData> ShareStatus(string content)
        {
            return await PostShuoStatus(content,null);
        }

        public override async Task<ResultData> ShareStatus(string content, System.IO.Stream image)
        {
            throw new NotImplementedException();
        }

        public override Task<ResultData> ShareStatusWithLocation(string content)
        {
            throw new NotImplementedException();
        }

        public override Task<ResultData> ShareStatusWithLocation(string content, Stream image)
        {
            throw new NotImplementedException();
        }

        public override Task<ResultData> ShareStatusWithLocation(string content, Uri imageUri)
        {
            throw new NotImplementedException();
        }

        public override Task<ResultData> ShareStatus(string content, Uri imageUri)
        {
            throw new NotImplementedException();
        }

        private async Task<ResultData> PostShuoStatus(string statusContent, Geoposition postion)
        {
            Uri uri = null;
            if (postion == null)
            {
                uri = new Uri("https://api.weibo.com/2/statuses/update.json?access_token=" + AccessToken + "&status=" + HttpUtility.UrlEncode(statusContent));
            }
            else
            {
                uri = new Uri("https://api.weibo.com/2/statuses/update.json?access_token=" + AccessToken + "&status=" + HttpUtility.UrlEncode(statusContent) + "&lat=" + postion.Coordinate.Latitude + "&long=" + postion.Coordinate.Longitude);
            }


            try
            {
                return await Utiltiy.HttpUtility.Post(uri,null, null, (webResponse) =>
                {
                    return new ResultData(this, ResultState.Success);
                });
            }
            catch (WebException webEx)
            {
                return WebExcptionHandler(webEx);
            }
            catch (Exception ex)
            {
                return new ResultData(this, ResultState.UnknowError, ex);
            }

            return null;
        }

        #endregion


        protected override System.IO.Stream ToStream()
        {
            System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SinaWeiboAuthInfor));
            System.IO.MemoryStream stream = new System.IO.MemoryStream();
            serializer.WriteObject(stream, new SinaWeiboAuthInfor()
            {
                UserID = this.UserID,
                AccessToken = this.AccessToken,
                ExpressDate = this.ExpressDate,
                AuthDate = this.AuthDate
            });
            stream.Seek(0, System.IO.SeekOrigin.Begin);
            return stream;
        }

        protected override void LoadFromeStrem(System.IO.Stream localData)
        {
            if (localData == null) return;
            System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SinaWeiboAuthInfor));
            System.IO.MemoryStream stream = new System.IO.MemoryStream();
            SinaWeiboAuthInfor authInfor = serializer.ReadObject(localData) as SinaWeiboAuthInfor;
            if (authInfor == null) return;
            this.AccessToken = authInfor.AccessToken;
            this.AuthDate = authInfor.AuthDate;
            this.ExpressDate = authInfor.ExpressDate;
            this.UserID = authInfor.UserID;
            IsAuthed = true;


        }

        private ResultData WebExcptionHandler(WebException webEx)
        {
            HttpWebResponse response = webEx.Response as HttpWebResponse;
            if (response == null) return new ResultData(this, ResultState.UnknowError);

            Dictionary<string, object> data = new Dictionary<string, object>();
            ResultState state = ResultState.UnknowError;
            try
            {

                using (System.IO.Stream stream = response.GetResponseStream())
                {
                    System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SinaWeiboErrorMessage));

                    SinaWeiboErrorMessage msg = serializer.ReadObject(response.GetResponseStream()) as SinaWeiboErrorMessage;

                    data.Add("Code", msg.Code);
                    data.Add("Error", msg.Error);
                    data.Add("Message", msg.Deiscription);
                    data.Add("Request", msg.Request);

                    switch (msg.Code)
                    {
                        case "21322":
                            state = ResultState.RedirectUriMismatch;
                            break;
                        case "21323":
                            state = ResultState.RequestForbidden;
                            break;
                        case "21324":
                            state = ResultState.InvalidAPIKey;
                            break;
                        case "21325":
                            state = ResultState.InvalidVerifyCode;
                            break;
                        default:
                            state = ResultState.UnknowError;
                            break;
                    }
                }
            }
            catch
            { 
            
            }


            return new ResultData(this, state, webEx, data);
        }


        [DataContract]
        private class SinaWeiboAuthInfor
        {
            [DataMember(Name = "access_token")]
            public string AccessToken { get; set; }

            [DataMember(Name = "expires_in")]
            public long ExpressionIn { get; set; }

            [DataMember(Name = "uid")]
            public string UserID { get; set; }

            [DataMember(Name = "Auth_Date")]
            public DateTime AuthDate { get; set; }

            [DataMember(Name = "Express_Date")]
            public DateTime ExpressDate { get; set; }



        }

        [DataContract]
        private class SinaWeiboErrorMessage
        {


            [DataMember(Name = "error")]
            public string Error { get; set; }

            [DataMember(Name = "error_code")]
            public string Code { get; set; }

            [DataMember(Name = "request")]
            public string Request { get; set; }

            [DataMember(Name = "error_uri")]
            public string ErrorUri { get; set; }


            [DataMember(Name = "error_description")]
            public string Deiscription { get; set; }
        }
    }
}
